package com.jianbing.mongo;

import com.jianbing.annotation.NotMongoField;
import com.jianbing.exception.ServiceException;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import org.apache.commons.beanutils.BeanUtils;
import org.bson.Document;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by Han, Tixiang on 2016/8/26 0026.
 */
public class MongoHelper {

    public static final int ASC = 1; //升序

    public static final int DESC = -1 ;//降序

    /**
     * 把实体bean对象转换成DBObject
     *
     * @param bean
     * @return
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     */
    public static <T> Document bean2Document(T bean) throws ServiceException {

        if (bean == null) {
            return null;
        }
        Document dbObject = new Document();
        // 获取对象对应类中的所有属性域
        Field[] fields = bean.getClass().getDeclaredFields();
        Field[] superFields = bean.getClass().getSuperclass().getDeclaredFields();
        setFieldIntoDocument(fields, dbObject, bean);
        setFieldIntoDocument(superFields, dbObject, bean);

        return dbObject;
    }

    private static <T> void setFieldIntoDocument(Field[] fields, Document dbObject, T bean) throws ServiceException {
        if (fields == null || fields.length == 0 || dbObject == null || bean == null) {
            return;
        }
        try {
            for (Field field : fields) {
                if (field.getAnnotation(NotMongoField.class) != null) {
                    continue;
                }
                // 获取属性名
                String varName = field.getName();
                if (varName.equals("_id")) {
                    continue;
                }
                // 修改访问控制权限
                boolean accessFlag = field.isAccessible();
                if (!accessFlag) {
                    field.setAccessible(true);
                }
                Object param = field.get(bean);
                if (param == null) {
                    continue;
                } else if (param instanceof Integer) {//判断变量的类型
                    int value = ((Integer) param).intValue();
                    dbObject.put(varName, value);
                } else if (param instanceof String) {
                    String value = (String) param;
                    dbObject.put(varName, value);
                } else if (param instanceof Double) {
                    double value = ((Double) param).doubleValue();
                    dbObject.put(varName, value);
                } else if (param instanceof Float) {
                    float value = ((Float) param).floatValue();
                    dbObject.put(varName, value);
                } else if (param instanceof Long) {
                    long value = ((Long) param).longValue();
                    dbObject.put(varName, value);
                } else if (param instanceof Boolean) {
                    boolean value = ((Boolean) param).booleanValue();
                    dbObject.put(varName, value);
                } else if (param instanceof Date) {
                    Date value = (Date) param;
                    dbObject.put(varName, value);
                } else if (param instanceof AtomicInteger) {
                    dbObject.put(varName, ((AtomicInteger) param).get());
                }
                // 恢复访问控制权限
                field.setAccessible(accessFlag);
            }
        } catch (IllegalAccessException e) {
            throw new ServiceException(e);
        }
    }


    public static <T> T document2Bean(Document dbObject, Class<T> clazz) throws ServiceException {
        try {
            if (clazz == null || dbObject == null) {
                return null;
            }
            Field[] fields = clazz.getDeclaredFields();
            Field[] superFields = clazz.getSuperclass().getDeclaredFields();

            T bean = clazz.newInstance();
            setProperties(fields, dbObject, bean);
            setProperties(superFields, dbObject, bean);
            return bean;
        } catch (Exception e) {
            throw new ServiceException(e);
        }
    }

    public static <T> T document2Bean(Document dbObject, T bean) throws ServiceException {
        if (bean == null || dbObject == null) {
            return null;
        }
        Field[] fields = bean.getClass().getDeclaredFields();
        Field[] superFields = bean.getClass().getSuperclass().getDeclaredFields();
        setProperties(fields, dbObject, bean);
        setProperties(superFields, dbObject, bean);
        return bean;
    }

    private static <T> void setProperties(Field[] fields, Document dbObject, T bean) throws ServiceException {
        if (fields == null || fields.length == 0 || dbObject == null || bean == null) {
            return;
        }
        try {
            for (Field field : fields) {
                if (field.getAnnotation(NotMongoField.class) != null) {
                    continue;
                }
                String varName = field.getName();
                Object object = dbObject.get(varName);
                if (object != null) {
                    if (field.getType() == AtomicInteger.class) {
                        object = new AtomicInteger(((Integer) object).intValue());
                    }
                    BeanUtils.setProperty(bean, varName, object);
                }
            }
        } catch (Exception e) {
            throw new ServiceException(e);
        }
    }
}